iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Mobile Development

30天,從0開始用Kotlin寫APP系列 第 24

Day 24 | Jetpack 與他的產物 - Room (Part 2)

  • 分享至 

  • xImage
  •  

Convert

在開發的時候有時需要存一些我們產生出來的類別型態到 SQLite 中,但 SQLite 本身並不支援這種型態,因此在寫入前需要先做一次轉換,讓他變成 SQLite 支援的型態

例如 SQLite 並不支援 Date 或是 DataTime 的格式,但是有支援 Long 型態,因此在寫入之前可以先把 Date 轉成 Longmilliseconds ,反之,在讀出來之後也要先把 Longmilliseconds 轉成 Date 再做使用

那在寫這種轉換時,需要在函式前面加上 @TypeConverter 裝飾詞, Room 會根據這個裝飾詞轉

class Converters {

    // 讀 milliseconds 出來轉成 Date
    @TypeConverter
    fun convertToEntityProperty(databaseValue: Long): Date {
        return Date(databaseValue)
    }

    // 把 Date 轉成 milliseconds 再存進去
    @TypeConverter
    fun convertToDatabaseValue(entityProperty: Date): Long {
        return entityProperty.time
    }
}

在定義完 Converter 類別後,就可以把這樣的規則加註到 Room Database 上,當 Room 在做存取的時候,就會依照這個規則下去做轉換

@Database(entities = [PirateInfoDao::class], version = 1, exportSchema = true)
@TypeConverters(Converters::class) // 把 Converters 加在這邊告訴 Room 有哪些需要被轉換
abstract class AppDatabase : RoomDatabase() {
    // 省略...
}

但是!但是!但是!
在我開開心心的把 App 跑起來的時候發現不太妙的事情,我以前這麼做都可以正常運作,但因為這次導入了我不熟悉的 Moshi ,因此在運行時一直有報錯的狀況,即使去做了一些調整,但還是沒把 Bug 解掉,因此我只好在快到 12 點之前先放棄了...

之後會在把這塊補上來,或是有大大可以給出一些建議,指點指點迷津

把資料存到 Room

那接下來就是要把資料存到 Room 裏面就算是完成今天的進度囉~
那我希望是在使用者執行 PirateDetailRepository 中的 fetchPirateInfo() ,就把資料順勢存到 SQLite 中,因此首先當然是先去加上 Insert 到 fetchPirateInfo()

那從下面的 Code 可以觀察到有幾個改變

  1. 加上了 Primary Constructor ,並在裏面加上了 private val pirateInfoDao: PirateInfoDao
  2. 在第 23 行加上了 pirateInfoDao.insertPirateInfo(pirateInfo) ,將物件 insert 到 Database 去
// PirateDetailRepository.kt

// 加上了 Primary Constructor ,參數是 PirateInfoDao
class PirateDetailRepository(private val pirateInfoDao: PirateInfoDao) {
    private val pirateService: PirateService =
        NetworkManager.provideRetrofit(NetworkManager.provideOkHttpClient())
            .create(PirateService::class.java)
    suspend fun fetchPirateInfo(
        pirateId: Int,
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) = flow<PirateInfo> {
        val response = pirateService.fetchPirateInfo(pirateId)
        response.suspendOnSuccess {
            if (data != null) {
                val pirateInfo: PirateInfo = data ?: PirateInfo(
                    id = 0,
                    name = "",
                    height = 0,
                    weight = 0,
                    attack = 0
                )
                pirateInfoDao.insertPirateInfo(pirateInfo)
                emit(pirateInfo)
                onSuccess()
            }
        }.onError {
            onError(message())
        }.onException {
            onError(message())
        }
    }.flowOn(Dispatchers.IO)
}

那對應的 ViewModel 的部份也需要做一些小調整

  1. 宣告 pirateDetailRepository,型態是 PirateDetailRepository?
  2. 加上 init{} 區塊,裡面會宣告 pirateInfoDao,而初始值是到 AppDatabase 取得 pirateInfoDao()
  3. 最後就是將 pirateInfoDao 加到 PirateDetailRepository() 的 Constructor 中
class GetPirateViewModel(application: Application) :
    AndroidViewModel(application) {
    private val pirateDetailRepository: PirateDetailRepository?

    fun pirateInfoLiveData(pirateId: Int): LiveData<PirateInfo> =
        liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
            pirateDetailRepository?.fetchPirateInfo(
                pirateId = pirateId,
                onSuccess = { },
                onError = { }
            )?.asLiveData()?.let {
                emitSource(it)
            }
        }

    init {
        val pirateInfoDao = AppDatabase.getInstance(application)?.pirateInfoDao()
        pirateDetailRepository = pirateInfoDao?.let { PirateDetailRepository(it) }
    }
}

到這邊就可以把資料存到 Database 裡面去了,但要怎麼確認資料有成功寫進去呢?有兩個方法可以知道

  1. 去把 Database 中所有資料拿回來確認(廢話~
  2. 用可視化工具確認(推荐)

在 Android Studio 4.0 之後是有內建的可視化工具可以確認資料庫目前的內容,但在之前如果要看到資料庫裏面的資料非常麻煩,要去裝個支援 SQLite 的工具,然後想辦法進到手機裏面,把 SQL 檔打包出來在丟進去看,光是要確認一個欄位就構開發者有的受的,因此 Facebook 推出了一個很讚的工具讓我們在開發時不用重複上述複雜的流程,那就是接下來要介紹的 Stetho

Stetho

Stetho 是 Facebook 開發的一款調適工具,他最大的特色是可以透過 Chrome DevTools 觀看即時的 App 數據

關於該如何使用可以看一篇我以前曾經寫過的介紹

那將程式跑下去,再到 chrom://inspect 中打開 Stetho 監聽的 App,就可以看到資料已經順順的進去資料庫囉~ (歡呼

總結

今天大致上把整個流程已經補的差不多了,但在寫 Code 和寫文章的過程中,還是會來來回回修改,因此文章教學結構上我個人覺得不太流暢,很多地方會感覺跳來跳去,但因為時間壓力的關係,目前只能先這樣子了,之後會在把這邊重構的更加完整,敬請期待,那明天會接續把取得 Pirate List 的 Code 補完

如果內容有任何問題或錯誤,歡迎提出與指教

Reference


上一篇
Day 23 | JetPack 與他的產物 - Room (Part 1)
下一篇
Day 25 | Jetpack 與他的產物 - Room (完結)
系列文
30天,從0開始用Kotlin寫APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言